home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr09
/
cascad13.zip
/
CASCADE.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-06-01
|
38KB
|
1,651 lines
PROGRAM deschart;
{Documentation is contained in the accompanying file CASCADE.DOC}
CONST
lines_per_page = 69;
lines_per_screen = 23;
indent_size = 5; {reduce this if you have very many generations to print}
maxfam = 2500; {increase this if there are more families in your database}
maxgen = 99; {default startup value and maximum;
can also be increased if necessary}
texlines_per_page = 46;
TYPE
twochr = string[2];
fchart = string[10];
fdate = string[20];
fmo = string[5];
fline = string[132];
indiv = {packed INDIV2.DAT record}
RECORD
data : ARRAY[1..92] of BYTE;
END;
irec = {unpacked INDIV2.DAT RECORD}
RECORD
surname : INTEGER;
given1 : INTEGER;
given2 : INTEGER;
given3 : INTEGER;
title : INTEGER;
sex : CHAR;
bdate : fdate;
bplace1 : INTEGER;
bplace2 : INTEGER;
bplace3 : INTEGER;
bplace4 : INTEGER;
cdate : fdate;
cplace1 : INTEGER;
cplace2 : INTEGER;
cplace3 : INTEGER;
cplace4 : INTEGER;
ddate : fdate;
dplace1 : INTEGER;
dplace2 : INTEGER;
dplace3 : INTEGER;
dplace4 : INTEGER;
budate : fdate;
buplace1 : INTEGER;
buplace2 : INTEGER;
buplace3 : INTEGER;
buplace4 : INTEGER;
bapdate : fdate;
baptemp : INTEGER;
endowdate : fdate;
endowtemp : INTEGER;
sealdate : fdate;
sealtemp : INTEGER;
sib : INTEGER;
marr : INTEGER;
pmarr : INTEGER;
id : ARRAY[1..10] of CHAR;
note : INTEGER;
END;
dict = {packed NAME2.DAT RECORD}
RECORD
lp : ARRAY[1..2] of BYTE;
name : ARRAY[1..17] of CHAR;
rp : ARRAY[1..2] of BYTE;
END; {PROCEDURE gn below unpacks NAME2.DAT RECORDs}
marr = {packed MARR2.DAT RECORD}
RECORD
data : ARRAY[1..28] of BYTE;
END;
mar = {unpacked MARR2.DAT RECORD}
RECORD
husb : INTEGER;
wife : INTEGER;
child : INTEGER;
mardate : fdate;
mplace1 : INTEGER;
mplace2 : INTEGER;
mplace3 : INTEGER;
mplace4 : INTEGER;
sealdate : fdate;
sealtemp : INTEGER;
hoth : INTEGER;
woth : INTEGER;
divflg : CHAR;
END;
genptr = ^genrec;
genrec = {pointer structure for recursively compiling descendants chart}
RECORD
mar : ARRAY[1..10] of INTEGER;
marptr : INTEGER;
child : ARRAY[1..30] of INTEGER;
chptr : INTEGER;
END;
ascptr = ^ascrec;
ascrec = {pointer structure for recursively ascending pedigree chart}
RECORD
marptr:INTEGER;
wifptr:INTEGER;
tafel:REAL;
lp,rp:ascptr;
END;
families =
RECORD
mrino,pg:INTEGER;
chrt:REAL;
END;
VAR
{files set up so that the standard function SEEK can locate
entries from RIN, name IN and MRIN respectively}
INDIV2 : file of indiv;
NAME2 : file of dict;
MARR2 : file of marr;
{configuration parameters}
paging,maleline,print_on,surname,index,printtofile,tex_on,marrln : BOOLEAN;
multmarr,skipfam,firstchart,bothrem,done,stackempty,alldone : BOOLEAN;
root,no_gen,nogen_up: INTEGER;
num,rin,page_no,texpage,line_ct,texline_ct : INTEGER;
i,j,blen,clen,dlen,bulen : INTEGER;
famsdone,wed_no,total_pages:INTEGER;
stacksize :INTEGER;
parents_marr : integer;
ans : CHAR;
hdg,texhdg,tmplin : fline;
namelin,blin,dlin,mlin : fline;
namelin2,blin2,dlin2: fline;
tex_blin2,tex_dlin2: fline;
skip,ref,ref2:fline;
file_name,index_entry,tex_nlin,tex_blin,tex_dlin,tex_mlin:fline;
orchart,orpg:INTEGER;
baserec:irec;
stacktop,p:ascptr;
famdone:ARRAY[1..maxfam] OF families;
chartno,maxchart:REAL;
index_file,prnfile,texfile:TEXT;
lastmarr,youngest:ARRAY[1..maxgen]OF BOOLEAN;
{i and j are global counters;
ans is CHAR response read from terminal;
lin is the output line for the individual currently being
processed;
done is false until current chart is finished}
PROCEDURE mainmenu;
BEGIN (*mainmenu*)
CLRSCR;
GOTOXY(32,2);
WRITE('CASCADE MAIN MENU');
GOTOXY(5,4);
WRITE('1. Toggle paging / scrolling (currently ');
IF paging THEN
WRITE('paging).')
ELSE
WRITE('scrolling).');
GOTOXY(5,5);
WRITE('2. Toggle all descendants / male line only (currently ');
IF maleline THEN
WRITE('male line only).')
ELSE
WRITE('all descendants).');
GOTOXY(5,6);
WRITE('3. Toggle printer on / off (currently ');
IF print_on THEN
WRITE('on).')
ELSE
WRITE('off).');
GOTOXY(5,7);
WRITE('4. Toggle cascading by surname / by generation (currently ');
IF surname THEN
WRITE('by surname).')
ELSE
WRITE('by generation).');
GOTOXY(5,8);
WRITE('5. Toggle index file creation on / off (currently ');
IF index THEN
WRITE('on).')
ELSE
WRITE('off).');
GOTOXY(5,9);
WRITE('6. Toggle print file creation on / off (currently ');
IF printtofile THEN
WRITE('on).')
ELSE
WRITE('off).');
GOTOXY(5,10);
WRITE('7. Toggle TeX file creation on / off (currently ');
IF tex_on THEN
WRITE('on).')
ELSE
WRITE('off).');
GOTOXY(5,11);
WRITE('8. Change no. of generations on a chart (currently ',no_gen,').');
GOTOXY(5,12);
WRITE('9. Change no. of generations to cascade (currently ',nogen_up,').');
GOTOXY(5,13);
WRITE('A. Change root individual (currently ',root,').');
GOTOXY(5,14);
WRITE('B. Produce a single descendants chart.');
GOTOXY(5,15);
WRITE('C. Produce cascading descendants charts.');
GOTOXY(5,17);
WRITE('0. Return to system.');
GOTOXY(1,20);
FOR j:= 1 TO 80 DO
WRITE('-');
GOTOXY(5,19);
WRITE('Selection : ')
END; {mainmenu}
FUNCTION flip(a1,a2:BYTE) : INTEGER;
{Reverse the BYTEs of INTEGER values which are stored lo,hi by
PAF. Arguments - two BYTEs. Returns an INTEGER.}
BEGIN {flip}
flip := a2*256+a1;
END; {flip}
FUNCTION mnth(mo:INTEGER) : fmo;
{Return month names - not completely coded here for all month
codes. Argument - month code - Returns 5 character string.}
BEGIN {mnth}
CASE mo OF
1: Mnth := ' Jan ';
2: Mnth := ' Feb ';
3: Mnth := ' Mar ';
4: Mnth := ' Apr ';
5: Mnth := ' May ';
6: Mnth := ' Jun ';
7: Mnth := ' Jul ';
8: Mnth := ' Aug ';
9: Mnth := ' Sep ';
10: Mnth := ' Oct ';
11: Mnth := ' Nov ';
12: Mnth := ' Dec ';
13: Mnth := 'NOTES';
ELSE Mnth := ' UNK ';
END; {case}
END; {mnth}
function time:fchart;
type
regpack = record
ax,bx,cx,dx,bp,si,di,ds,es,flags: integer;
end;
var
recpack: regpack; {assign record}
ah,al,ch,cl,dh: byte;
hour,min,sec: string[2];
begin
ah := $2c; {initialize correct registers}
with recpack do
begin
ax := ah shl 8 + al;
end;
intr($21,recpack); {call interrupt}
with recpack do
begin
str(cx shr 8,hour); {convert to string}
IF cx shr 8 < 10 THEN
hour := '0'+hour;
str(cx mod 256,min); { " }
IF cx mod 256 < 10 THEN
min := '0'+min;
str(dx shr 8,sec); { " }
IF dx shr 8 < 10 THEN
sec := '0'+sec;
end;
time := ' '+hour+':'+min+':'+sec+' ';
end;
function Date: fdate;
type
regpack = record
ax,bx,cx,dx,bp,si,di,ds,es,flags: integer;
end;
var
recpack: regpack; {record for MsDos call}
month,day: string[2];
year: string[4];
dx,cx: integer;
begin
with recpack do
begin
ax := $2a shl 8;
end;
MsDos(recpack); { call function }
with recpack do
begin
str(cx,year); {convert to string}
str(dx mod 256,day); { " }
date := day + mnth(dx shr 8) + year + time;
end;
end;
PROCEDURE gn(yx:INTEGER;VAR leng:INTEGER;VAR nam:fdate);
{Return a name string and its length from the NAME2.DAT file. The
length is important because this string must be concatenated
character by character up to the length. If this is not done,
extraneous data from your NAME2 file will appear in your output.
Arguments - NAME2.DAT identification number. Output - name and
its length.}
VAR
n : dict; {packed yx-th line of NAME2.DAT}
i : INTEGER;
BEGIN {gn}
SEEK(NAME2,yx);
READ(NAME2,n);
IF yx > 0 THEN
BEGIN
nam := n.name;
leng := pos(chr(0),nam) - 1;
END
ELSE
BEGIN
nam := '';
leng := -1;
END
END; {gn}
PROCEDURE xdate(a1,a2,a3,a4:BYTE;VAR res:fdate);
{Extracts a packed date into a printable string. Arguments - four
BYTEs of packed date. Output - date string. Main year is in
second half of first BYTE and first half of second BYTE; month is
in next 5 bits; day in next 5 bits; modifier in next 2 bits; and
alternate year - e.g. 1987/1988 - in last BYTE.}
VAR
yr,mo,day,mfr : INTEGER;
x : string[4];
y,z : string[2];
BEGIN {xdate}
yr := a1*16+ a2 div 16;
mo := (a2-(a2 div 16)*16)*2 + a3 div 128;
day := (a3-(a3 div 128)*128) div 4;
mfr := a3-(a3 div 4)*4;
str(yr:4,x);
str(day:2,z);
CASE mfr OF
0: IF (yr > 0) or (mo > 0) or (day > 0) THEN
res := 'Bef '
ELSE
res := '';
1: res := 'Abt ';
2: res := '';
3: res := 'Aft ';
END;
IF day > 0 THEN
res := res+z;
IF mo > 0 THEN
res := res+MNTH(mo);
IF yr > 0 THEN
res := res+x;
IF a4 <> 0 THEN
BEGIN
yr := yr + a4;
str(yr:4,x);
res := res+'/'+x;
END;
END; {xdate}
PROCEDURE unp_marr(marriage:marr;VAR x:mar);
{Extract MARR2.DAT information into useable form. Arguments -
packed MARR2.DAT line. Output - unpacked marriage RECORD.}
VAR
i : INTEGER;
BEGIN {unp_marr}
WITH marriage,x DO
BEGIN {with}
husb := flip(data[1],data[2]);
wIFe := flip(data[3],data[4]);
child := flip(data[5],data[6]);
xdate(data[7],data[8],data[9],data[10],mardate);
mplace1 := flip(data[11],data[12]);
mplace2 := flip(data[13],data[14]);
mplace3 := flip(data[15],data[16]);
mplace4 := flip(data[17],data[18]);
xdate(data[19],data[20],data[21],0,sealdate);
sealtemp := flip(data[22],data[23]);
hoth := flip(data[24],data[25]);
woth := flip(data[26],data[27]);
divflg := chr(data[28]);
END; {with}
END; {unp_marr}
PROCEDURE unpack(pers:indiv;VAR x:irec);
{Extract INDIV2.DAT information into useable form. Arguments -
Individual RECORD in BYTEs. Output - Individual RECORD expanded.}
VAR
i : INTEGER;
BEGIN {unpack}
WITH pers,x DO
BEGIN {with}
surname := flip(data[1],data[2]);
given1 := flip(data[3],data[4]);
given2 := flip(data[5],data[6]);
given3 := flip(data[7],data[8]);
title := flip(data[9],data[10]);
sex := chr(data[11]);
xdate(data[12],data[13],data[14],data[15],bdate);
bplace1 := flip(data[16],data[17]);
bplace2 := flip(data[18],data[19]);
bplace3 := flip(data[20],data[21]);
bplace4 := flip(data[22],data[23]);
xdate(data[24],data[25],data[26],data[27],cdate);
cplace1 := flip(data[28],data[29]);
cplace2 := flip(data[30],data[31]);
cplace3 := flip(data[32],data[33]);
cplace4 := flip(data[34],data[35]);
xdate(data[36],data[37],data[38],data[39],ddate);
dplace1 := flip(data[40],data[41]);
dplace2 := flip(data[42],data[43]);
dplace3 := flip(data[44],data[45]);
dplace4 := flip(data[46],data[47]);
xdate(data[48],data[49],data[50],data[51],budate);
buplace1 := flip(data[52],data[53]);
buplace2 := flip(data[54],data[55]);
buplace3 := flip(data[56],data[57]);
buplace4 := flip(data[58],data[59]);
xdate(data[60],data[61],data[62],0,bapdate);
baptemp := flip(data[63],data[64]);
xdate(data[65],data[66],data[67],0,endowdate);
endowtemp := flip(data[68],data[69]);
xdate(data[70],data[71],data[72],0,sealdate);
sealtemp := flip(data[73],data[74]);
sib := flip(data[75],data[76]);
marr := flip(data[77],data[78]);
pmarr := flip(data[79],data[80]);
for i := 1 to 10 DO
id[i] := chr(data[80+i]);
note := flip(data[91],data[92]);
END; {with}
END; {unpack}
PROCEDURE getnames(given1,given2,given3,surname,title,j:INTEGER;
VAR namlin,texlin:fline);
VAR
xx : fdate;
temp:fline;
i,len : INTEGER;
y : string[1];
yy : string[2];
yyy : string[3];
yyyy : string[4];
yyyyy : string[5];
cht:fchart;
pg:fmo;
PROCEDURE addname;
BEGIN
IF len > 0 THEN
BEGIN
FOR i := 1 to len DO
BEGIN
namlin := namlin+xx[i];
IF index THEN
index_entry := index_entry+xx[i]
END;
namlin := namlin+' ';
IF index THEN
index_entry := index_entry+' '
END
END;
BEGIN {getnames}
namlin := '';
temp:='';
IF index THEN
index_entry := '';
gn(given1,len,xx);
addname;
gn(given2,len,xx);
addname;
gn(given3,len,xx);
addname;
gn(surname,len,xx);
IF index THEN
index_entry := ', ' + index_entry;
IF len > 0 THEN
BEGIN
FOR i := 1 to len DO {capitalise surname}
IF (xx[i] >= 'a') and (xx[i] <='z') THEN
xx[i]:=chr(ord(xx[i])-32);
IF (xx[1]='M') AND (xx[2]='C') THEN
xx[2]:='c';
IF (xx[1]='M') AND (xx[2]='A') AND (xx[3]='C') THEN
BEGIN
xx[2]:='a';
xx[3]:='c'
END;
IF xx[3]=' ' THEN {De, N\'i, and suchlike}
xx[2]:=chr(ord(xx[2])+32);
FOR i := 1 to len DO
BEGIN
namlin := namlin+xx[i];
IF index THEN
temp:= temp+xx[i];
END;
namlin := namlin+' ';
IF index THEN
index_entry := temp + index_entry
END;
gn(title,len,xx);
addname;
texlin:=namlin;
IF j>9999 THEN
BEGIN
str(j:5,yyyyy);
namlin := namlin+'('+yyyyy+')';
IF index THEN
index_entry:=index_entry+'('+yyyyy+')'
END
ELSE
IF j>999 THEN
BEGIN
str(j:4,yyyy);
namlin := namlin+'('+yyyy+')';
IF index THEN
index_entry:=index_entry+'('+yyyy+')'
END
ELSE
IF j>99 THEN
BEGIN
str(j:3,yyy);
namlin := namlin+'('+yyy+')';
IF index THEN
index_entry:=index_entry+'('+yyy+')'
END
ELSE
IF j>9 THEN
BEGIN
str(j:2,yy);
namlin := namlin+'('+yy+')';
IF index THEN
index_entry:=index_entry+'('+yy+')'
END
ELSE
BEGIN
str(j:1,y);
namlin:=namlin+'('+y+')';
IF index THEN
index_entry:=index_entry+'('+y+')'
END;
If index THEN
BEGIN
STR(chartno:1:0,cht);
index_entry:=index_entry+' Chart '+cht;
IF NOT tex_on THEN
BEGIN
STR(page_no:4,pg);
index_entry:=index_entry+' Page'+pg
END
ELSE
BEGIN
STR(texpage:4,pg);
index_entry:=index_entry+' Page'+pg
END;
WRITELN(index_file,index_entry)
END
END; {getnames}
PROCEDURE getdateplace
(date:fdate;place1,place2,place3,place4:INTEGER; VAR
lin:fline;VAR texlin:fline; VAR leng:INTEGER);
{The following lengthy routine extracts the best available date and place
information for a birth/christening, marriage or death/burial
and adds it to the output string. It may cause
runtime overflow if too much information is available.}
VAR
firstname:boolean;
xx : fdate;
i,len,offset : INTEGER;
PROCEDURE addname;
BEGIN {addname}
IF firstname THEN {first place}
BEGIN
firstname:=false;
texlin := texlin + ' \it '
END
ELSE
BEGIN {subsequent places}
texlin:=texlin + ' ';
offset:=offset+1
END;
FOR i := 1 to len DO
BEGIN
lin := lin+xx[i];
texlin:=texlin+xx[i]
END;
lin := lin + ',';
texlin:=texlin + ',';
leng := leng + len + 1;
END; {addname}
BEGIN {getdateplace}
firstname:=TRUE;
lin := '';
texlin := '';
leng := 0;
offset:=5;
IF length(date) > 3 THEN
BEGIN
lin := date + ' ';
texlin := date;
offset:=offset-1;
leng := length(date) + 1
END;
gn(place1,len,xx);
IF len > 0 THEN
addname;
gn(place2,len,xx);
IF len > 0 THEN
addname;
gn(place3,len,xx);
IF len > 0 THEN
addname;
gn(place4,len,xx);
IF len > 0 THEN
addname;
IF leng > (length(date) + 1) THEN
IF lin[leng-1]='.' THEN
BEGIN
lin[leng]:=' ';
texlin[leng+offset]:=' '
END
ELSE
BEGIN
lin[leng]:='.';
texlin[leng+offset]:='.'
END
END; {getdateplace}
PROCEDURE getperson(ind:irec; rin:INTEGER; VAR
namlin,birlin,birtex,dealin,deatex:fline; VAR
birlen,chrlen,dealen,burlen:INTEGER);
BEGIN {getperson}
WITH ind DO
BEGIN {with}
getnames(given1,given2,given3,
surname,title,rin,namlin,tmplin);
getdateplace(bdate,bplace1,bplace2,bplace3,
bplace4,birlin,birtex,birlen);
IF birlen=0 THEN
getdateplace(cdate,cplace1,cplace2,cplace3,
cplace4,birlin,birtex,chrlen);
getdateplace(ddate,dplace1,dplace2,dplace3,
dplace4,dealin,deatex,dealen);
IF dealen=0 THEN
getdateplace(budate,buplace1,buplace2,
buplace3,buplace4,dealin,deatex,burlen);
END; {with}
END; {getperson}
{PROCEDURE to build the line of information about an individual
which will be printed in the descendants chart. Arguments - An
INTEGER RIN (j is the VARiable). Output - a line of information
<name,title,RIN,birthdate,birthplace,deathdate,deathplace>}
PROCEDURE wait;
BEGIN {wait}
GOTOXY(5,24);
WRITE('Press <Enter> to continue ... ');
READ(ans)
END; {wait}
PROCEDURE heading;
{Produce a heading at the top of the page}
VAR
dash:INTEGER;
BEGIN {heading}
IF page_no<>1 THEN
BEGIN
IF printtofile THEN
WRITELN(prnfile,chr(12));
IF print_on THEN
WRITELN(lst,chr(12)) {FF}
END
ELSE
IF firstchart AND print_on THEN
BEGIN {first page}
firstchart:=FALSE;
GOTOXY(9,23);
WRITELN('Adjust printer to top of page. Do not switch it off');
wait
END; {first page}
IF print_on THEN
BEGIN
WRITELN(lst);
WRITELN(lst);
WRITE(lst,chr(27),chr(14));
WRITE(lst,'DESCENDANTS CHART FOR:');
WRITELN(lst);
WRITELN(lst);
WRITE(lst,chr(27),chr(14));
WRITELN(lst,hdg);
WRITELN(lst);
WRITE(lst,chr(27),chr(14));
WRITE(lst,date,' Chart No:',chartno:10:0);
WRITE(lst,' Page No:',page_no:4);
WRITELN(lst);
WRITELN(lst);
FOR dash:=1 to 132 DO
WRITE(lst,'-');
WRITELN(lst);
WRITELN(lst)
END;
IF printtofile THEN
BEGIN
WRITELN(prnfile);
WRITELN(prnfile);
WRITE(prnfile,chr(27),chr(14));
WRITE(prnfile,'DESCENDANTS CHART FOR:');
WRITELN(prnfile);
WRITELN(prnfile);
WRITE(prnfile,chr(27),chr(14));
WRITELN(prnfile,hdg);
WRITELN(prnfile);
WRITE(prnfile,chr(27),chr(14));
WRITE(prnfile,date,' Chart No:',chartno:10:0);
WRITE(prnfile,' Page No:',page_no:4);
WRITELN(prnfile);
WRITELN(prnfile);
FOR dash:=1 to 132 DO
WRITE(prnfile,'-');
WRITELN(prnfile);
WRITELN(prnfile)
END
END; {heading}
PROCEDURE indent (j:INTEGER; VAR lin:fline);
VAR
i,k:INTEGER;
BEGIN {indent}
lin := '';
IF j>1 THEN
BEGIN
FOR i := 2 TO j-1 DO
BEGIN
FOR k := 1 TO indent_size-1 DO
lin := lin + ' ';
IF youngest[i] AND lastmarr[i] THEN
lin := lin + ' '
ELSE
lin := lin + '|'
END;
FOR k := 1 TO indent_size-1 DO
lin := lin + ' ';
lin:=lin + '|'
END
END; {indent}
PROCEDURE tex_indent (j:INTEGER; VAR lin:fline);
VAR
i:INTEGER;
BEGIN {tex_indent}
lin := '';
IF j>1 THEN
BEGIN
FOR i := 2 TO j-1 DO
BEGIN
lin := lin + '\>';
IF NOT (youngest[i] AND lastmarr[i]) THEN
lin := lin + '$|$'
END;
lin := lin + '\>$|$'
END
END; {tex_indent}
PROCEDURE lineout(lin,tex_line:fline;marrline:boolean);
BEGIN {lineout}
WRITELN(lin); {first the output to screen}
line_ct := succ(line_ct);
IF ((line_ct MOD lines_per_screen = 0) AND paging) THEN
BEGIN
WRITELN;
GOTOXY(5,24);
WRITE('Press S<Enter> to toggle scrolling,');
WRITE(' <Enter> to continue ... ');
READ(ans);
IF (ans='s') OR (ans='S') THEN
paging:=FALSE;
WRITELN
END;
IF line_ct MOD lines_per_page = 0 THEN
page_no:=succ(page_no);
IF print_on THEN {second the output to ASCII printer}
BEGIN
WRITELN(lst,lin);
IF Line_ct MOD Lines_Per_Page = 0
THEN heading
END;
IF printtofile THEN {third the output to print file}
BEGIN
WRITELN(prnfile,lin);
IF Line_ct MOD Lines_Per_Page = 0
THEN heading
END;
IF tex_on THEN {fourth and last the output to TeX file}
BEGIN
WRITE(texfile,tex_line);
IF NOT marrline THEN
WRITELN(texfile,'\\');
texline_ct := succ(texline_ct);
IF texline_ct MOD texlines_Per_Page = 0 THEN
BEGIN
texpage:=succ(texpage);
WRITELN(texfile,'\end{paftab}');
WRITELN(texfile,'\begin{paftab}')
END
END
END; {lineout}
PROCEDURE outperson(rin,gen:INTEGER;yy:twochr;VAR pers:irec);
VAR
ind:indiv;
BEGIN {outperson}
SEEK(INDIV2,rin);
READ(INDIV2,ind);
unpack(ind,pers);
getperson(pers,rin,namelin2,blin2,tex_blin2,dlin2,tex_dlin2,
blen,clen,dlen,bulen);
indent(gen,namelin);
tex_indent(gen,tex_nlin);
namelin := namelin + yy + '-' + namelin2;
tex_nlin := tex_nlin + yy + ' -- \bf ' + namelin2;
lineout(namelin,tex_nlin,marrln);
indent(gen,blin);
tex_indent(gen,tex_blin);
IF blen <> 0 THEN
BEGIN
blin := blin + ' -b. ' + blin2;
tex_blin := tex_blin + '\ b. ' + tex_blin2;
lineout(blin,tex_blin,marrln)
END
ELSE
IF clen <> 0 THEN
BEGIN
blin := blin + ' -chr. ' + blin2;
tex_blin := tex_blin + '\ chr. ' + tex_blin2;
lineout(blin,tex_blin,marrln)
END;
indent(gen,dlin);
tex_indent(gen,tex_dlin);
IF dlen <> 0 THEN
BEGIN
dlin := dlin + ' -d. ' + dlin2;
tex_dlin := tex_dlin + '\ d. ' + tex_dlin2;
lineout(dlin,tex_dlin,marrln)
END
ELSE
IF bulen <> 0 THEN
BEGIN
dlin := dlin + ' -bur. ' + dlin2;
tex_dlin := tex_dlin + '\ bur. ' + tex_dlin2;
lineout(dlin,tex_dlin,marrln)
END;
END; {out_person}
PROCEDURE out_marr(wedding:mar;gen:INTEGER);
VAR
tex_mlin2,mlin2:fline;
mlen:INTEGER;
marr_no:string[1];
BEGIN {out_marr}
WITH wedding DO
BEGIN
indent(gen,mlin);
tex_indent(gen,tex_mlin);
getdateplace(mardate,mplace1,mplace2,mplace3,
mplace4,mlin2,tex_mlin2,mlen);
mlin := mlin + ' -m.';
tex_mlin := tex_mlin + '\ m.';
IF multmarr THEN
BEGIN
str(wed_no,marr_no);
mlin := mlin + '(' + marr_no + ')';
tex_mlin := tex_mlin + '(' + marr_no + ')'
END;
mlin := mlin + ' ' + mlin2;
IF tex_mlin2 <> '' THEN
tex_mlin := tex_mlin + ' ' + tex_mlin2;
marrln:=TRUE;
lineout(mlin,tex_mlin,marrln);
marrln:=FALSE;
END
END; {out_marr}
PROCEDURE prsetup(rin:INTEGER);
VAR
ind:indiv;
pers:irec;
temp:boolean;
BEGIN {prsetup}
SEEK(INDIV2,rin);
READ(INDIV2,ind);
unpack(ind,pers);
temp:=index;
index:=false; {to prevent duplicate index entry for heading individual}
WITH pers DO
getnames(given1,given2,given3,surname,title,rin,hdg,texhdg);
index:=temp;
IF NOT bothrem THEN
BEGIN
total_pages:=total_pages+page_no;
page_no := 1;
texpage:=1
END
ELSE
bothrem := false;
line_ct := 1;
texline_ct := 1;
IF print_on OR printtofile THEN
heading;
END; {prsetup}
PROCEDURE getroot(VAR rin:INTEGER; VAR pers:irec);
VAR
ind:indiv;
BEGIN {getroot}
GOTOXY(9,21);
WRITE('Enter the RIN: ');
READ(rin);
SEEK(INDIV2,rin);
READ(INDIV2,ind);
unpack(ind,pers)
END; {getroot}
PROCEDURE startoutput;
BEGIN {startoutput}
IF index THEN
BEGIN
GOTOXY(9,21);
WRITE('Index file will be cleared!! ');
WRITE('Use another program to sort the index file.');
GOTOXY(9,22);
WRITE('Enter full pathname for index file : ');
READLN(file_name);
ASSIGN(index_file,file_name);
REWRITE(index_file);
IF printtofile OR tex_on THEN {tidy display}
mainmenu
END;
IF printtofile THEN
BEGIN
GOTOXY(9,21);
WRITE('Print file will be cleared!!');
GOTOXY(9,22);
WRITE('Enter full pathname for print file : ');
READLN(file_name);
ASSIGN(prnfile,file_name);
REWRITE(prnfile);
IF tex_on THEN
mainmenu
END;
IF tex_on THEN
BEGIN
GOTOXY(9,21);
WRITE('Use default file TEMP.TEX? (Y/N): ');
READLN(ans);
IF (ans='Y') OR (ans='y') THEN
file_name:='temp.tex'
ELSE
BEGIN
GOTOXY(9,21);
WRITE('TeX file will be cleared!! Extension must be .TeX');
GOTOXY(9,22);
WRITE('Enter full pathname for TeX file : ');
READLN(file_name)
END;
ASSIGN(texfile,file_name);
REWRITE(texfile)
END
END; {startoutput}
PROCEDURE nodups(mrin:INTEGER;VAR skip:BOOLEAN;VAR chart,page:INTEGER);
{Procedure to check whether and on which chart the offspring of
the current marriage have already appeared.}
VAR
i:INTEGER;
BEGIN {nodups}
i:=1;
WHILE (i<=famsdone) AND (famdone[i].mrino<>mrin) DO
i:=i+1;
skip:= (i<>famsdone+1);
IF skip THEN
BEGIN
chart:=round(famdone[i].chrt); {must be an integer}
page:=famdone[i].pg
END
ELSE
BEGIN
famsdone:=famsdone+1;
WITH famdone[i] DO
BEGIN
mrino:=mrin;
chrt:=chartno;
IF tex_on THEN
pg:=texpage
ELSE
pg:=page_no
END
END
END; {nodups}
PROCEDURE descend_top(rin:INTEGER);
{Top level of the Descent Chart Process.}
VAR
ind:indiv;
pers:irec;
i:INTEGER;
PROCEDURE descend(rin,gen:INTEGER);
{Recursive sub-procedure to traverse the family descent and print
the lines of the descent chart. This routine must be studied
carefully to understand. The basic functions are:
1. Print the individual referred to by RIN.
2. Build a list of all marriages of that person.
3. For each marriage:
a. Print the spouse - IF any.
b. Build a list of all children of the marriage.
c. For each child (in order of birth):
1) Recurse down one generation.
Arguments - RIN, generation #. Output - the report.}
VAR
i,j,k,m,curr_mar,curr_child : INTEGER;
yy : string[2];
ind,ind1 : indiv;
pers,pers1 : irec;
m1 : marr;
m2 : mar;
p : genptr;
g : genrec;
done,temptex : BOOLEAN;
tempstr : fchart;
temp : string[1];
BEGIN {descend}
SEEK(INDIV2,rin);
READ(INDIV2,ind1);
unpack(ind1,pers1);
IF (gen<=No_Gen) AND (NOT maleline OR (pers1.sex='M')) THEN
BEGIN {output}
IF gen<10 THEN
BEGIN
str(gen:1,temp);
yy:=temp + ' '
END
ELSE
str(gen:2,yy);
outperson(rin,gen,yy,pers);
IF pers.marr <> 0 THEN
BEGIN {LOOK AT ALL MARRIAGES}
new(p);
p^.marptr := 0;
p^.chptr := 0;
done := False;
m := pers.marr;
i := 1;
WHILE NOT done DO
BEGIN {LOOK AT ANOTHER MARRIAGE}
SEEK(MARR2,m);
READ(MARR2,m1);
unp_marr(m1,m2);
p^.marptr := i;
p^.mar[i] := m;
IF pers.sex = 'M' THEN
IF m2.hoth <> 0 THEN
BEGIN
m := m2.hoth;
i := i+1;
END
ELSE
done := True
ELSE
IF m2.woth <> 0 THEN
BEGIN
m := m2.woth;
i := i+1;
END
ELSE
done := True;
END; {LOOK AT ANOTHER MARRIAGE}
FOR j := 1 to p^.marptr DO
BEGIN {PROCESS jTH MARRIAGE}
curr_mar := p^.mar[j];
SEEK(MARR2,curr_mar);
READ(MARR2,m1);
unp_marr(m1,m2);
wed_no:=j;
multmarr:=(p^.marptr<>1);
lastmarr[gen]:=(j=p^.marptr);
out_marr(m2,gen);
IF m2.child <> 0 THEN
BEGIN {see if already output}
nodups(curr_mar,skipfam,orchart,orpg);
IF tex_on THEN
IF skipfam THEN
BEGIN {omit all children}
WRITE(texfile,'\protect\footnote{');
WRITE(texfile,'See chart no.\ ');
WRITE(texfile,orchart,' page no.\ ');
WRITE(texfile,orpg,' for descendants.');
WRITE(texfile,'}')
END {omit all children}
END; {see if already output}
IF tex_on THEN
WRITELN(texfile,'\\');
IF pers.sex = 'M' THEN
IF m2.wIFe <> 0 THEN
BEGIN
yy := 's ';
outperson(m2.wife,
gen,yy,pers1);
END;
IF pers.sex = 'F' THEN
IF m2.husb <> 0 THEN
BEGIN
yy := 's ';
outperson(m2.husb,
gen,yy,pers1);
END;
IF m2.child <> 0 THEN
BEGIN {see if already output}
IF skipfam THEN
BEGIN {omit all children}
temptex:=tex_on;
tex_on:=false;{disable since fn done}
indent(gen,ref2);
lineout(ref2,tex_mlin,marrln);
ref2:=ref2+'See chart no. ';
STR(orchart:10,tempstr);
ref2:=ref2+tempstr;
ref2:=ref2+' page no.';
STR(orpg:5,tempstr);
ref2:=ref2+tempstr;
ref2:=ref2+' for descendants.';
lineout(ref2,tex_mlin,marrln);
indent(gen,ref2);
lineout(ref2,tex_mlin,marrln);
tex_on:=temptex
END {omit all children}
ELSE
BEGIN { COLLECT CHILDREN}
p^.chptr := 1;
done := False;
k := m2.child;
p^.child[p^.chptr]:=k;
while not done DO
BEGIN {GET NEXT CHILD}
SEEK(INDIV2,k);
READ(INDIV2,ind1);
unpack(ind1,pers1);
IF pers1.sib<>0 THEN
BEGIN
p^.chptr:=p^.chptr+1;
k := pers1.sib;
p^.child[p^.chptr]:=k;
END
ELSE
done := True;
END; {GET NEXT CHILD}
END {COLLECT CHILDREN}
END; {see if already output}
FOR i := p^.chptr downto 1 DO
BEGIN
curr_child := p^.child[i];
youngest[gen+1]:=(i=1);
descend(curr_child,gen+1);
END;
p^.chptr := 0;
END; {process jth marriage}
END; {look at all marriages}
mark(p);
END; {output}
END; {descend}
BEGIN {Main body of descend_top; process an entire chart}
prsetup(rin);
CLRSCR;
WRITELN(no_gen,' Generation chart (no. ',chartno:1:0,') for ',hdg);
IF tex_on THEN
BEGIN
WRITE(texfile,'\begin{chart}');
WRITELN(texfile,'{',chartno:1:0,'}{',texhdg,'}{',rin,'}');
WRITELN(texfile,'\begin{paftab}')
END;
descend(rin,1);
IF print_on THEN
WRITE(lst,chr(12)); { FF }
IF printtofile THEN
WRITE(prnfile,chr(12));
IF tex_on THEN
WRITELN(texfile,'\end{paftab}\end{chart}');
IF paging THEN
BEGIN
writeln;
wait
END
END; {descend_top}
PROCEDURE ascend(wedding:INTEGER);
VAR
m1:marr;
m2:mar;
da,ma:indiv;
father,mother:irec;
FUNCTION doachart(whoever:irec):BOOLEAN;
BEGIN
doachart:=(whoever.pmarr=0) OR (chartno>=maxchart/2)
END;
PROCEDURE pop;
VAR
tmptr:ascptr;
BEGIN {pop}
IF stacksize > 0 THEN
BEGIN {pop stack}
stacksize:=stacksize-1;
tmptr:=p;
p:=p^.lp;
WITH tmptr^ DO
begin
chartno := tafel;
parents_marr := marptr;
end;
END {pop stack}
else
alldone := true
END; {pop}
BEGIN {ascend}
IF wedding <> 0 THEN
BEGIN {unpack and process}
SEEK(MARR2,wedding);
READ(MARR2,m1);
unp_marr(m1,m2);
IF m2.husb <> 0 THEN
BEGIN
SEEK(INDIV2,m2.husb);
READ(INDIV2,da);
unpack(da,father);
END;
IF (m2.wIFe <> 0) AND (chartno<maxchart/2) THEN
BEGIN {stack maternal side}
stacksize:=stacksize+1;
SEEK(INDIV2,m2.wIFe);
READ(INDIV2,ma);
unpack(ma,mother);
IF stacksize=1 THEN
BEGIN
new(stacktop);
p:=stacktop;
END
ELSE
BEGIN
new(p^.rp);
p^.rp^.lp:=p;
p:=p^.rp;
END;
p^.marptr:=mother.pmarr;
p^.wIFptr:=m2.wIFe;
p^.tafel:=2*chartno+1;
END; {stack maternal side}
WITH m2 DO
BEGIN {next chart}
IF woth <> 0 THEN
BEGIN {other wives}
IF surname THEN
BEGIN
IF doachart(mother) THEN
descend_top(wife)
END
ELSE
descend_top(wife);
IF hoth <> 0 THEN
IF surname THEN
BEGIN
IF doachart(father) THEN
descend_top(husb)
END
ELSE
BEGIN
WRITE('Both spouses');
WRITE('remarried');
WRITE(' - printing 2');
WRITELN(' charts (same number)');
bothrem:=true;
descend_top(husb)
END
END {other wives}
ELSE
IF husb <> 0 THEN
IF surname THEN
BEGIN
IF doachart(father) THEN
descend_top(husb)
END
ELSE
descend_top(husb)
ELSE
IF surname THEN
BEGIN
IF doachart(mother) THEN
descend_top(wife)
END
ELSE
descend_top(wife);
IF (husb <> 0) AND (chartno<maxchart/2) THEN
begin
parents_marr := father.pmarr;
chartno := 2*chartno
end
ELSE
pop
END {next chart}
END {unpack and process}
ELSE
IF chartno=1 THEN
BEGIN {no ancestors}
GOTOXY(9,21);
WRITE('No ancestors entered for this');
WRITE(' person. (RIN: ',root,'.)');
GOTOXY(9,22);
IF baserec.sex = 'M' THEN
WRITE('His ')
ELSE
WRITE('Her ');
WRITE('descendants chart will be printed.');
wait;
descend_top(root);
alldone:=TRUE
END {no ancestors}
ELSE
pop
END; {ascend}
PROCEDURE statistics;
BEGIN {statistics}
WRITELN;
WRITELN('Total number of families (with children) processed: ',famsdone);
WRITELN;
WRITELN('Total number of pages printed: ',total_pages);
WRITELN;
wait;
IF index THEN
close(index_file);
IF printtofile THEN
close(prnfile);
IF tex_on THEN
close(texfile)
END; {statistics}
PROCEDURE cascade;
BEGIN {cascade}
stacksize:=0;
total_pages:=0;
startoutput;
parents_marr := baserec.pmarr;
alldone := false;
REPEAT
ascend(parents_marr)
UNTIL alldone;
total_pages:=total_pages+page_no;
statistics
END; {cascade}
PROCEDURE getdata;
{The DOS SUBST command should be used to make E: correspond to
the appropriate pathname.}
BEGIN {getdata}
ASSIGN(NAME2,'E:NAME2.DAT');
RESET(NAME2);
ASSIGN(INDIV2,'E:INDIV2.DAT');
RESET(INDIV2);
ASSIGN(MARR2,'E:MARR2.DAT');
RESET(MARR2);
END; {getdata}
PROCEDURE welcome;
BEGIN {welcome}
CLRSCR;
GOTOXY(11,2);
WRITE('Welcome to CASCADE: a PAF utility program by Patrick Waldron');
GOTOXY(11,3);
WRITE('============================================================');
GOTOXY(31,5);
WRITE(date);
GOTOXY(29,7);
WRITE('Version 1.3. 17 Feb 1991.');
GOTOXY(1,9);
WRITELN('*WARNING* Before running CASCADE, it is essential to issue the');
WRITELN(' DOS command "subst e: <pathname>" where <pathname> is');
WRITELN(' the location of your PAF data files. Otherwise, an I/O');
WRITELN(' error will occur when you now hit <Enter>.');
GOTOXY(1,14);
WRITE('If you find this program useful please send IR#10 or equivalent to');
GOTOXY(9,15);
WRITE('P. J. M. Waldron');
GOTOXY(9,16);
WRITE('39 Park Drive');
GOTOXY(9,17);
WRITE('Dublin 6');
GOTOXY(9,18);
WRITE('IRELAND');
GOTOXY(1,19);
WRITE('or to your favourite charity.');
GOTOXY(1,21);
WRITE('Send a SASE or 2 IRCs to the above address if you have queries,');
WRITELN(' bug reports');
WRITE('or suggestions, or if you want information on updates.');
wait
END; {welcome}
PROCEDURE initialise;
VAR
ind:indiv;
BEGIN {initialise}
marrln:=FALSE;
paging:=TRUE;
maleline:=FALSE;
print_on:=FALSE;
surname:=FALSE;
index:=FALSE;
printtofile:=FALSE;
tex_on:=FALSE;
no_gen:=maxgen;
nogen_up:=6;
maxchart:=64;
root:=1;
SEEK(INDIV2,root);
READ(INDIV2,ind);
unpack(ind,baserec)
END; {initialise}
PROCEDURE switchprinteron;
BEGIN {switchprinteron}
IF print_on THEN
BEGIN
GOTOXY(1,21);
WRITELN('Initialising printer ... ');
WRITELN('Switch on printer/adjust to TOF.');
wait;
WRITE(lst,chr(27)+'0',chr(15))
END
ELSE
WRITE(lst,chr(27)+'@')
END; {switchprinteron}
PROCEDURE gencheck;
BEGIN
IF surname AND (nogen_up>=no_gen) THEN
BEGIN
nogen_up:=no_gen-1;
maxchart:=exp(nogen_up*ln(2));
mainmenu;
GOTOXY(9,21);
WRITE('***** WARNING ***** (see CASCADE.DOC)');
GOTOXY(9,22);
WRITE('Surname option requires minimum generations per chart.');
GOTOXY(9,23);
WRITE('No. of generations to cascade has been reset to ');
WRITE(nogen_up,'.');
wait
END
END;
BEGIN {main}
done := false;
bothrem:= false;
welcome;
getdata;
initialise;
while not done DO
BEGIN {WHILE}
famsdone:=0;
page_no:=0;
texpage:=0;
chartno:=1;
firstchart:=TRUE;
mainmenu;
READLN(Ans);
CASE ans OF
'1': paging:=NOT paging;
'2': maleline:=NOT maleline;
'3': BEGIN
print_on := NOT print_on;
switchprinteron
END;
'4': BEGIN
surname := NOT surname;
gencheck
END;
'5': index:=NOT index;
'6': printtofile:=NOT printtofile;
'7': tex_on:=NOT tex_on;
'8': BEGIN
GOTOXY(9,21);
WRITE('How many generations on each descendants chart? ');
READ(no_gen);
gencheck
END;
'9': BEGIN
GOTOXY(9,21);
WRITE('Cascade back how many generations? ');
READ(nogen_up);
maxchart:=exp(nogen_up*ln(2));
gencheck
END;
'A': getroot(root,baserec);
'a': getroot(root,baserec);
'B': BEGIN
startoutput;
descend_top(root);
total_pages:=page_no;
statistics
END;
'b': BEGIN
startoutput;
descend_top(root);
total_pages:=page_no;
statistics
END;
'C': IF maleline THEN
BEGIN
GOTOXY(9,21);
WRITE('Cannot cascade with maleline flag on.');
wait
END
ELSE
cascade;
'c': IF maleline THEN
BEGIN
GOTOXY(9,21);
WRITE('Cannot cascade with maleline flag on.');
wait
END
ELSE
cascade;
'0': done := true
END {CASE}
END; {WHILE}
CLRSCR
END. {main}